"""
    此种方法不一定得出正确答案，但在不断的调整字母频率表过程中，相较于最初始的频率表，已经十分接近最终答案。
    在运行一遍程序后，通过调整后的频率表解密出的明文依旧存在错误，通过比较原单词（明文中的大写单词）与纠错单词（纠错中的小写单词）
    手动修改初始频率表，再次运行程序，直至明文符合逻辑或者纠错过程未发现单词错误。

    tip：ETANIOSHLDPRCMFUGYXWKBVQZJ
"""

from spellchecker import SpellChecker

# 字母频率表
frequency_list = "ETAOINSHRDLCUMWFGYPBVKJXQZ"


# frequency_list="ETANIOSHLDPRCMFUGYXWKBVQZJ"

# 计算密文中各字母的数目
def count_letters(ciphertext):
    letter_counts = {}
    for letter in ciphertext:
        if letter.isalpha():  # 判断是否为字母
            if letter in letter_counts:
                letter_counts[letter] += 1
            else:
                letter_counts[letter] = 1
    return letter_counts


# 秘钥表
def key_list(ciphertext):
    key_table = {}
    letter_counts = count_letters(ciphertext)  # 统计密文中每个字母出现的次数
    sorted_letters = sorted(letter_counts.items(), key=lambda x: x[1], reverse=True)  # 按出现次数排序
    for i in range(len(sorted_letters)):
        key_table[sorted_letters[i][0]] = frequency_list[i]
    return key_table


# 解密
def decode(ciphertext, key_table):
    plaintext = ""
    for letter in ciphertext:
        if letter.isalpha():
            plaintext += key_table[letter]
        else:
            plaintext += letter
    return plaintext  # 返回明文


def word_replace(words):  # 拼写检查，单词替换，替换结果为小写
    c_words = []  # 正确单词表
    for word in words:
        if word in spell:  # 判断该单词是否在词典中
            c_words.append(word)
        else:  # 若不在，则比较给出的最合适替换单词与原单词长度是否一致，若不一致则从候选表中选择长度一致的单词
            if spell.correction(word):
                if len(spell.correction(word)) == len(word):
                    c_words.append(spell.correction(word))
                else:  # 从候选表中选择，若无，则不替换
                    suggestions = spell.candidates(word)
                    if suggestions:
                        f = False
                        for i in suggestions:
                            if len(word) == len(i):
                                c_words.append(i)
                                f = True
                                break
                        if not f:
                            c_words.append(word)
            else:
                c_words.append(word)
    return c_words


# 频率分析法解密
def frequency_decrypt(ciphertext):
    key_table = key_list(ciphertext)
    plaintext = decode(ciphertext, key_table)
    return plaintext


# 测试代码
if __name__ == "__main__":
    ciphertext = "WB WI KJB MK RMIT BMIQ BJ RASHMWK RMVP YJERYRKB MKD WBI IWOKWXWVMKVR MKD IJYR YNIB URYMWK NKRASHMWKRD BJ OWER M VJYSHRBR RASHMKMBWJK JKR CJNHD PMER BJ LR FNMHWXWRD MKD WKISWURD BJ INVP MK RABRKB BPMB PR VJNHD URMVP BPR IBMBR JX RKHWOPBRKRD YWKD VMSMLHR JX URVJOKWGWKO IJNKDHRII IJNKD MKD IPMSRHRII IPMSR W DJ KJB DRRY YTIRHX BPR XWKMH MNBPJUWBT LNB YT RASRUWRKVR CWBP QMBM PMI HRXB KJ DJNLB BPMB BPR XJHHJCWKO WI BPR SUJSRU MSSHWVMBWJK MKD WKBRUSURBMBWJK W JXXRU YT BPRJUWRI WK BPR PJSR BPMB BPR RIIRKVR JX JQWKMCMK QMUMBR CWHH URYMWK WKBMVB"
    print("密文:", ciphertext)
    plaintext = frequency_decrypt(ciphertext)
    print("明文:", plaintext)
    words = plaintext.split()
    spell = SpellChecker(language='en')  # 英文词典库
    FLAG = 0  # 在进行修改频率表时，此变量表示比较至哪一单词
    while True:
        error_now = 0  # 统计经过拼写检查后错误单词数目
        corrected_words = word_replace(words)
        print("纠错:", " ".join(corrected_words))
        for i, j in zip(words, corrected_words):
            if i != j:
                error_now += 1
        if error_now != 0 and FLAG != len(words):
            num = 0
            m = n = ''
            for i, j in zip(words[FLAG:], corrected_words[FLAG:]):
                num = 0
                FLAG += 1
                if i != j:  # 当某一单词拼写检查后仅与原单词相差一位时，认为该位有错误，重新修改频率表，已经比较过的单词将不再重新比较，避免死循环
                    for p, q in zip(i.lower(), j):
                        if p != q:
                            num += 1
                            m = p
                            n = q
                    if num == 1:
                        frequency_list = frequency_list.replace(m.upper(), m)
                        frequency_list = frequency_list.replace(n.upper(), n)
                        frequency_list = frequency_list.replace(m, n.upper())
                        frequency_list = frequency_list.replace(n, m.upper())
                        print(f"\n交换{m.upper()}、{n.upper()}后频率表：", frequency_list)
                        plaintext = frequency_decrypt(ciphertext)
                        words = plaintext.split()
                        print("明文:", plaintext)
                        break
        else:
            break
    corrected_s = " ".join(corrected_words)
    print("\n频率表:", frequency_list)
    print("密文:", ciphertext)
    print("明文:", plaintext)
    print("纠错:", corrected_s)
    print("\n结果:", corrected_s.lower())
